package collect;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import com.google.common.base.Function;

/**
 * Additional useful static Function methods to complement the Guava functions.
 * @author Carl A. Pearson
 * @version 1.0
 */
public class Functions {

	/**
	 * Returns a function for fetching {@link Future}s.
	 * TODO: allow options other than the default barfing/non-timeout singleton; continue to implement as static-factory.
	 * @param <T> the type
	 * @return the function
	 */
	@SuppressWarnings("unchecked")
	public static <T> Function<Future<T>,T> getter() {
		return (Function<Future<T>,T>)getter;
	}
	
	/**
	 * The singleton used by {@link #getter()}.
	 * <p>
	 * Does not time out.
	 * <p>
	 * Barfs exceptions to System.err and returns null.
	 */
	private static final Function<? extends Future<?>,?> getter = new Function<Future<Object>,Object>() {
		@Override public Object apply(Future<Object> from) {
			try {
				return from.get();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
			return null;
		}
	};
	
	/**
	 * Like {@link #getter()}, but will return a default value on exceptions.
	 * @param <T> the type
	 * @param defaultValue the result of a function when an exception occurs during
	 * the get call
	 * @return {@code f(future) => interrupted ? default : future.get()}
	 */
	public static <T> Function<Future<T>,T> defaultingGetter(final T defaultValue) {
		return new Function<Future<T>,T>() {
			@Override public T apply(Future<T> from) {
				try {
					return from.get();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (ExecutionException e) {
					e.printStackTrace();
				}
				return defaultValue;
			}
		};
	}
	
	/**
	 * A Function for converting jobs into futures by submitting them to the provided
	 * {@link ExecutorService}.
	 * <p>
	 * Applying this function lazily defeats the purpose of threading the jobs.
	 * @param <T> the type returned by the Future
	 * @param e the service Callables are submitted to
	 * @return {@code f(callable) => future}
	 */
	public static <T> Function<Callable<T>,Future<T>> threader(final ExecutorService e) {
		return new Function<Callable<T>,Future<T>>() {
			@Override public Future<T> apply(Callable<T> from) { return e.submit(from); }
		};
	}
	
}
